﻿using SafeLoad.NControl.Assist;
using System;
using System.Collections.Generic;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;

namespace SafeLoad.NControl
{
  /// <summary>
  /// NCurve.xaml 的交互逻辑
  /// </summary>
  public partial class NCurve : UserControl
  {
    #region Constrctor

    public NCurve()
    {
      InitializeComponent();

            random = new Random();
            data_list = new Dictionary<string, NCurveItem>();
            auxiliary_lines = new List<AuxiliaryLine>();
            markTexts = new List<NMarkText>();
            auxiliary_Labels = new List<AuxiliaryLabel>();
        }

    protected override void OnRender(DrawingContext drawingContext)
    {
      base.OnRender(drawingContext);
      NCurveUpdate();
    }

    public static void RenderUpdateByPropertyChanged(DependencyObject dependency, DependencyPropertyChangedEventArgs e)
    {
      if (dependency is NCurve curve)
      {
        curve.NCurveUpdate();
      }
    }
        #endregion

        #region Data Member

        Dictionary<string, NCurveItem> data_list = null;  // 等待显示的实际数据
        private string[] data_text = null;                  // 等待显示的横轴信息

        #endregion

        #region Public Properties

        /// <summary>
        /// 获取或设置图形的纵坐标的最大值，该值必须大于最小值
        /// </summary>
        public double ValueMaxLeft
        {
            get { return (double)GetValue(ValueMaxLeftProperty); }
            set { SetValue(ValueMaxLeftProperty, value); }
        }
        public static readonly DependencyProperty ValueMaxLeftProperty =
            DependencyProperty.Register("ValueMaxLeft", typeof(double), typeof(NCurve), new PropertyMetadata(100d,
                new PropertyChangedCallback(RenderUpdateByPropertyChanged)));

        /// <summary>
        /// 获取或设置图形的纵坐标的最小值，该值必须小于最大值
        /// </summary>
        public double ValueMinLeft
        {
            get { return (double)GetValue(ValueMinLeftProperty); }
            set { SetValue(ValueMinLeftProperty, value); }
        }
        public static readonly DependencyProperty ValueMinLeftProperty =
            DependencyProperty.Register("ValueMinLeft", typeof(double), typeof(NCurve), new PropertyMetadata(0d,
                new PropertyChangedCallback(RenderUpdateByPropertyChanged)));

        /// <summary>
        /// 获取或设置图形的纵轴分段数
        /// </summary>
        public int ValueSegment
        {
            get { return (int)GetValue(ValueSegmentProperty); }
            set { SetValue(ValueSegmentProperty, value); }
        }
        public static readonly DependencyProperty ValueSegmentProperty =
            DependencyProperty.Register("ValueSegment", typeof(int), typeof(NCurve), new PropertyMetadata(5,
                new PropertyChangedCallback(RenderUpdateByPropertyChanged)));

        /// <summary>
        /// 获取或设置所有的数据是否强制在一个界面里显示
        /// </summary>
        public bool IsAbscissaStrech
        {
            get { return (bool)GetValue(IsAbscissaStrechProperty); }
            set { SetValue(IsAbscissaStrechProperty, value); }
        }

        // Using a DependencyProperty as the backing store for IsAbscissaStrech.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty IsAbscissaStrechProperty =
            DependencyProperty.Register("IsAbscissaStrech", typeof(bool), typeof(NCurve), new PropertyMetadata(false,
                new PropertyChangedCallback(RenderUpdateByPropertyChanged)));

        /// <summary>
        /// 获取或设置拉伸模式下的最大数据量
        /// </summary>
        public int StrechDataCountMax
        {
            get { return (int)GetValue(StrechDataCountMaxProperty); }
            set { SetValue(StrechDataCountMaxProperty, value); }
        }

        // Using a DependencyProperty as the backing store for StrechDataCountMax.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty StrechDataCountMaxProperty =
            DependencyProperty.Register("StrechDataCountMax", typeof(int), typeof(NCurve), new PropertyMetadata(300,
                new PropertyChangedCallback(RenderUpdateByPropertyChanged)));

        /// <summary>
        /// 获取或设置虚线是否进行显示
        /// </summary>
        public bool IsRenderDashLine
        {
            get { return (bool)GetValue(IsRenderDashLineProperty); }
            set { SetValue(IsRenderDashLineProperty, value); }
        }

        // Using a DependencyProperty as the backing store for IsRenderDashLine.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty IsRenderDashLineProperty =
            DependencyProperty.Register("IsRenderDashLine", typeof(bool), typeof(NCurve), new PropertyMetadata(true,
                new PropertyChangedCallback(RenderUpdateByPropertyChanged)));

        /// <summary>
        /// 获取或设置坐标轴及相关信息文本的颜色
        /// </summary>
        public Color ColorLinesAndText
        {
            get { return (Color)GetValue(ColorLinesAndTextProperty); }
            set { SetValue(ColorLinesAndTextProperty, value); }
        }

        // Using a DependencyProperty as the backing store for ColorLinesAndText.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty ColorLinesAndTextProperty =
            DependencyProperty.Register("ColorLinesAndText", typeof(Color), typeof(NCurve), new PropertyMetadata(Colors.DimGray,
                new PropertyChangedCallback(RenderUpdateByPropertyChanged)));

        /// <summary>
        /// 获取或设置虚线的颜色
        /// </summary>
        public Color ColorDashLines
        {
            get { return (Color)GetValue(ColorDashLinesProperty); }
            set { SetValue(ColorDashLinesProperty, value); }
        }

        // Using a DependencyProperty as the backing store for ColorDashLines.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty ColorDashLinesProperty =
            DependencyProperty.Register("ColorDashLines", typeof(Color), typeof(NCurve), new PropertyMetadata(Colors.Gray,
                new PropertyChangedCallback(RenderUpdateByPropertyChanged)));

        /// <summary>
        /// 获取或设置纵向虚线的分隔情况，单位为多少个数据
        /// </summary>
        public int IntervalAbscissaText
        {
            get { return (int)GetValue(IntervalAbscissaTextProperty); }
            set { SetValue(IntervalAbscissaTextProperty, value); }
        }

        // Using a DependencyProperty as the backing store for IntervalAbscissaText.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty IntervalAbscissaTextProperty =
            DependencyProperty.Register("IntervalAbscissaText", typeof(int), typeof(NCurve), new PropertyMetadata(100,
                new PropertyChangedCallback(RenderUpdateByPropertyChanged)));

        /// <summary>
        /// 获取或设置实时数据新增时文本相对应于时间的格式化字符串，默认HH:mm
        /// </summary>
        public string TextAddFormat
        {
            get { return (string)GetValue(TextAddFormatProperty); }
            set { SetValue(TextAddFormatProperty, value); }
        }

        // Using a DependencyProperty as the backing store for TextAddFormat.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty TextAddFormatProperty =
            DependencyProperty.Register("TextAddFormat", typeof(string), typeof(NCurve), new PropertyMetadata("HH:mm",
                new PropertyChangedCallback(RenderUpdateByPropertyChanged)));

        /// <summary>
        /// 获取或设置图标的标题信息
        /// </summary>
        public string Title
        {
            get { return (string)GetValue(TitleProperty); }
            set { SetValue(TitleProperty, value); }
        }
        public static readonly DependencyProperty TitleProperty =
            DependencyProperty.Register("Title", typeof(string), typeof(NCurve), new PropertyMetadata(string.Empty,
                new PropertyChangedCallback(RenderUpdateByPropertyChanged)));

        public int TitleFontSize
        {
            get { return (int)GetValue(TitleFontSizeProperty); }
            set { SetValue(TitleFontSizeProperty, value); }
        }
        public static readonly DependencyProperty TitleFontSizeProperty =
            DependencyProperty.Register("TitleFontSize", typeof(int), typeof(NCurve), new PropertyMetadata(12,
                new PropertyChangedCallback(RenderUpdateByPropertyChanged)));

        /// <summary>
        /// 获取或设置曲线名称的布局宽度，默认为100
        /// </summary>
        public int CurveNameWidth
        {
            get { return (int)GetValue(CurveNameWidthProperty); }
            set { SetValue(CurveNameWidthProperty, value); }
        }

        // Using a DependencyProperty as the backing store for CurveNameWidth.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty CurveNameWidthProperty =
            DependencyProperty.Register("CurveNameWidth", typeof(int), typeof(NCurve), new PropertyMetadata(100,
                new PropertyChangedCallback(RenderUpdateByPropertyChanged)));

        /// <summary>
        /// 获取或设置数据点的大小
        /// </summary>
        public int PointsRadius
        {
            get { return (int)GetValue(PointsRadiusProperty); }
            set { SetValue(PointsRadiusProperty, value); }
        }

        // Using a DependencyProperty as the backing store for PointsRadius.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty PointsRadiusProperty =
            DependencyProperty.Register("PointsRadius", typeof(int), typeof(NCurve), new PropertyMetadata(0,
                new PropertyChangedCallback(RenderUpdateByPropertyChanged)));



        #endregion

        #region Public Method

        /// <summary>
        /// 设置曲线的横坐标文本，适用于显示一些固定的曲线信息
        /// </summary>
        /// <param name="descriptions">应该和曲线的点数一致</param>
        public void SetCurveText(string[] descriptions)
        {
            data_text = descriptions;

            // 重绘图形
            NCurveUpdate();
        }

        /// <summary>
        /// 新增或修改一条指定关键字的左参考系曲线数据，需要指定数据，颜色随机，没有数据上限，线条宽度为1
        /// </summary>
        /// <param name="key">曲线关键字</param>
        /// <param name="data">曲线的具体数据</param>
        public void SetCurve(string key, double[] data)
        {
            SetCurve(key, data, Color.FromRgb((byte)random.Next(256), (byte)random.Next(256), (byte)random.Next(256)));
        }


        /// <summary>
        /// 新增或修改一条指定关键字的左参考系曲线数据，需要指定数据，颜色，没有数据上限，线条宽度为1
        /// </summary>
        /// <param name="key">曲线关键字</param>
        /// <param name="data">数据内容</param>
        /// <param name="lineColor">曲线颜色</param>
        public void SetCurve(string key, double[] data, Color lineColor)
        {
            SetCurve(key, data, lineColor, 1f, CurveStyle.LineSegment);
        }

        /// <summary>
        /// 新增或修改一条指定关键字的左参考系曲线数据，需要指定数据，颜色，没有数据上限，线条宽度为1
        /// </summary>
        /// <param name="key">曲线关键字</param>
        /// <param name="data">数据内容</param>
        /// <param name="lineColor">曲线颜色</param>
        /// <param name="style">曲线的样式</param>
        public void SetCurve(string key, double[] data, Color lineColor, CurveStyle style)
        {
            SetCurve(key, data, lineColor, 1f, style);
        }


        /// <summary>
        /// 新增或修改一条指定关键字的曲线数据，需要指定参考系及数据，颜色，线条宽度
        /// </summary>
        /// <param name="key">曲线关键字</param>
        /// <param name="data">数据</param>
        /// <param name="lineColor">线条颜色</param>
        /// <param name="thickness">线条宽度</param>
        /// <param name="style">曲线的样式</param>
        public void SetCurve(string key, double[] data, Color lColor, float thickness, CurveStyle style)
        {
            if (data_list.ContainsKey(key))
            {
                if (data == null) data = new double[] { };
                data_list[key].Data = data;
            }
            else
            {
                if (data == null) data = new double[] { };
                data_list.Add(key, new NCurveItem()
                {
                    Data = data,
                    MarkText = new string[data.Length],
                    LineThickness = thickness,
                    LineColor = lColor,
                    Style = style,
                });

                if (data_text == null)
                {
                    data_text = new string[data.Length];
                }
            }

            // 重绘图形
            NCurveUpdate();
        }


        /// <summary>
        /// 移除指定关键字的曲线
        /// </summary>
        /// <param name="key">曲线关键字</param>
        public void RemoveCurve(string key)
        {
            if (data_list.ContainsKey(key))
            {
                data_list.Remove(key);
            }
            if (data_list.Count == 0)
            {
                data_text = new string[0];
            }
            // 重绘图形
            NCurveUpdate();
        }

        /// <summary>
        /// 移除所有的曲线
        /// </summary>
        public void RemoveAllCurve()
        {
            int count = data_list.Count;
            data_list.Clear();
            if (data_list.Count == 0)
            {
                data_text = new string[0];
            }
            // 重绘图形
            if (count > 0) NCurveUpdate();
        }

        /// <summary>
        /// 移除所有曲线的数据
        /// </summary>
        public void RemoveAllCurveData()
        {
            int count = data_list.Count;

            foreach (var item in data_list)
            {
                item.Value.Data = new double[0];
                item.Value.MarkText = new string[0];
            }
            data_text = new string[0];

            // 重绘图形
            if (count > 0) NCurveUpdate();
        }

        /// <summary>
        /// 获取曲线图中已经存在的曲线对象，用于动态修改一些复杂的数据信息，如线宽，标记点，修改以前的数据内容等等
        /// </summary>
        /// <param name="key">关键字</param>
        /// <returns>曲线对象信息</returns>
        public NCurveItem GetCurveItem(string key)
        {
            if (data_list.ContainsKey(key))
            {
                return data_list[key];
            }
            else
            {
                return null;
            }
        }

        // ======================================================================================================


        /// <summary>
        /// 新增指定关键字曲线的一个数据，注意该关键字的曲线必须存在，否则无效
        /// </summary>
        /// <param name="key">新增曲线的关键字</param>
        /// <param name="values">数据值</param>
        /// <param name="markTexts">标记的文本信息</param>
        /// <param name="isUpdateUI">是否刷新界面</param>
        private void AddCurveData(string key, double[] values, string[] markTexts, bool isUpdateUI)
        {
            if (values?.Length < 1) return;                              // 没有传入数据

            if (data_list.ContainsKey(key))
            {
                NCurveItem curve = data_list[key];
                if (curve.Data != null)
                {
                    if (IsAbscissaStrech)
                    {
                        // 填充玩整个图形的情况
                        NHelper.AddArrayData(ref curve.Data, values, StrechDataCountMax);
                        NHelper.AddArrayData(ref curve.MarkText, markTexts, StrechDataCountMax);
                    }
                    else
                    {
                        // 指定点的情况，必然存在最大值情况
                        NHelper.AddArrayData(ref curve.Data, values, value_count_max);
                        NHelper.AddArrayData(ref curve.MarkText, markTexts, value_count_max);
                    }

                    if (isUpdateUI) NCurveUpdate();
                }
            }
        }

        // 新增曲线的时间节点
        private void AddCurveTime(int count)
        {
            AddCurveTime(count, DateTime.Now.ToString(TextAddFormat));
        }

        private void AddCurveTime(int count, string text)
        {
            if (data_text == null) return;
            string[] values = new string[count];
            for (int i = 0; i < values.Length; i++)
            {
                values[i] = text;
            }


            if (IsAbscissaStrech)
            {
                NHelper.AddArrayData(ref data_text, values, StrechDataCountMax);
            }
            else
            {
                NHelper.AddArrayData(ref data_text, values, value_count_max);
            }
        }

        /// <summary>
        /// 新增指定关键字曲线的一个数据，注意该关键字的曲线必须存在，否则无效
        /// </summary>
        /// <param name="key">曲线的关键字</param>
        /// <param name="value">数据值</param>
        public void AddCurveData(string key, double value)
        {
            AddCurveData(key, new double[] { value });
        }

        /// <summary>
        /// 新增指定关键字曲线的一个数据，注意该关键字的曲线必须存在，否则无效
        /// </summary>
        /// <param name="key">曲线的关键字</param>
        /// <param name="value">数据值</param>
        /// <param name="markText">标记的本文信息</param>
        public void AddCurveData(string key, double value, string markText)
        {
            AddCurveData(key, new double[] { value }, new string[] { markText });
        }

        /// <summary>
        /// 新增指定关键字曲线的一组数据，注意该关键字的曲线必须存在，否则无效
        /// </summary>
        /// <param name="key">曲线的关键字</param>
        /// <param name="values">数组值</param>
        public void AddCurveData(string key, double[] values)
        {
            AddCurveData(key, values, null);
        }


        /// <summary>
        /// 新增指定关键字曲线的一组数据，注意该关键字的曲线必须存在，否则无效
        /// </summary>
        /// <param name="key">曲线的关键字</param>
        /// <param name="values">数组值</param>
        /// <param name="markTexts">标记的本文信息</param>
        public void AddCurveData(string key, double[] values, string[] markTexts)
        {
            if (markTexts == null) markTexts = new string[values.Length];

            AddCurveData(key, values, markTexts, false);
            if (values?.Length > 0)
            {
                AddCurveTime(values.Length);
            }
            NCurveUpdate();
        }

        /// <summary>
        /// 新增指定关键字数组曲线的一组数据，注意该关键字的曲线必须存在，否则无效，一个数据对应一个数组
        /// </summary>
        /// <param name="keys">曲线的关键字数组</param>
        /// <param name="values">数组值</param>
        public void AddCurveData(string[] keys, double[] values)
        {
            AddCurveData(keys, values, null);
        }

        /// <summary>
        /// 新增指定关键字数组曲线的一组数据，注意该关键字的曲线必须存在，否则无效，一个数据对应一个数组
        /// </summary>
        /// <param name="axisText">自定义的横轴坐标数据</param>
        /// <param name="keys">曲线的关键字数组</param>
        /// <param name="values">数组值</param>
        public void AddCurveData(string axisText, string[] keys, double[] values)
        {
            AddCurveData(axisText, keys, values, null);
        }

        /// <summary>
        /// 新增指定关键字数组曲线的一组数据，注意该关键字的曲线必须存在，否则无效，一个数据对应一个数组
        /// </summary>
        /// <param name="keys">曲线的关键字数组</param>
        /// <param name="values">数组值</param>
        /// <param name="markTexts">标记的文本信息</param>
        public void AddCurveData(string[] keys, double[] values, string[] markTexts)
        {
            if (keys == null) throw new ArgumentNullException("keys");
            if (values == null) throw new ArgumentNullException("values");
            if (markTexts == null) markTexts = new string[keys.Length];
            if (keys.Length != values.Length) throw new Exception("两个参数的数组长度不一致。");
            if (keys.Length != markTexts.Length) throw new Exception("两个参数的数组长度不一致。");

            for (int i = 0; i < keys.Length; i++)
            {
                AddCurveData(keys[i], new double[] { values[i] }, new string[] { markTexts[i] }, false);
            }

            AddCurveTime(1);
            // 统一的更新显示
            NCurveUpdate();
        }

        /// <summary>
        /// 新增指定关键字数组曲线的一组数据，注意该关键字的曲线必须存在，否则无效，一个数据对应一个数组
        /// </summary>
        /// <param name="axisText">自定义的横轴坐标数据</param>
        /// <param name="keys">曲线的关键字数组</param>
        /// <param name="values">数组值</param>
        /// <param name="markTexts">标记的文本信息</param>
        public void AddCurveData(string axisText, string[] keys, double[] values, string[] markTexts)
        {
            if (keys == null) throw new ArgumentNullException("keys");
            if (values == null) throw new ArgumentNullException("values");
            if (markTexts == null) markTexts = new string[keys.Length];
            if (keys.Length != values.Length) throw new Exception("两个参数的数组长度不一致。");
            if (keys.Length != markTexts.Length) throw new Exception("两个参数的数组长度不一致。");

            for (int i = 0; i < keys.Length; i++)
            {
                AddCurveData(keys[i], new double[] { values[i] }, new string[] { markTexts[i] }, false);
            }

            AddCurveTime(1, axisText);
            // 统一的更新显示
            NCurveUpdate();
        }

        /// <summary>
        /// 设置一条曲线是否是可见的，如果该曲线不存在，则无效。
        /// </summary>
        /// <param name="key">关键字</param>
        /// <param name="visible">是否可见</param>
        public void SetCurveVisible(string key, bool visible)
        {
            if (data_list.ContainsKey(key))
            {
                NCurveItem curve = data_list[key];
                curve.Visible = visible;
                NCurveUpdate();
            }
        }

        /// <summary>
        /// 设置多条曲线是否是可见的，如果该曲线不存在，则无效。
        /// </summary>
        /// <param name="keys">关键字</param>
        /// <param name="visible">是否可见</param>
        public void SetCurveVisible(string[] keys, bool visible)
        {
            foreach (var key in keys)
            {
                if (data_list.ContainsKey(key))
                {
                    NCurveItem curve = data_list[key];
                    curve.Visible = visible;
                }
            }
            NCurveUpdate();
        }


        #endregion

        #region Auxiliary Line

        // 辅助线的信息，允许自定义辅助线信息，来标注特殊的线条

        private List<AuxiliaryLine> auxiliary_lines;               // 所有辅助线的列表

        /// <summary>
        /// 新增一条辅助线，使用默认的文本颜色
        /// </summary>
        /// <param name="value">数据值</param>
        public void AddAuxiliary(float value)
        {
            AddAuxiliary(value, ColorLinesAndText);
        }

        /// <summary>
        /// 新增一条左侧的辅助线，使用指定的颜色
        /// </summary>
        /// <param name="value">数据值</param>
        /// <param name="lineColor">线条颜色</param>
        public void AddAuxiliary(float value, Color lineColor)
        {
            AddAuxiliary(value, lineColor, 1f, true);
        }

        private void AddAuxiliary(float value, Color lColor, float lineThickness, bool isDashLine)
        {
            auxiliary_lines.Add(new AuxiliaryLine()
            {
                Value = value,
                LineColor = lColor,
                IsDashStyle = isDashLine,
                LineThickness = lineThickness,
            });
            NCurveUpdate();
        }

        /// <summary>
        /// 移除所有的指定值的辅助曲线
        /// </summary>
        /// <param name="value"></param>
        public void RemoveAuxiliary(float value)
        {
            int removeCount = 0;
            for (int i = auxiliary_lines.Count - 1; i >= 0; i--)
            {
                if (auxiliary_lines[i].Value == value)
                {
                    auxiliary_lines.RemoveAt(i);
                    removeCount++;
                }
            }
            if (removeCount > 0) NCurveUpdate();
        }


        /// <summary>
        /// 移除所有的辅助线
        /// </summary>
        public void RemoveAllAuxiliary()
        {
            int removeCount = auxiliary_lines.Count;
            auxiliary_lines.Clear();

            if (removeCount > 0) NCurveUpdate();
        }


        #endregion

        #region Auxiliary Lable

        // 辅助线的信息，允许自定义辅助线信息，来标注特殊的线条

        private List<AuxiliaryLabel> auxiliary_Labels;               // 所有辅助线的列表

        /// <summary>
        /// 新增一条辅助标签
        /// </summary>
        /// <param name="auxiliaryLable">描述的标签值</param>
        public void AddAuxiliaryLabel(AuxiliaryLabel auxiliaryLable)
        {
            auxiliary_Labels.Add(auxiliaryLable);
            NCurveUpdate();
        }

        /// <summary>
        /// 移除指定的辅助标签
        /// </summary>
        /// <param name="auxiliaryLable">等待删除的对象</param>
        public void RemoveAuxiliaryLable(AuxiliaryLabel auxiliaryLable)
        {
            if (auxiliary_Labels.Remove(auxiliaryLable)) NCurveUpdate();
        }

        /// <summary>
        /// 移除所有的辅助标签
        /// </summary>
        public void RemoveAllAuxiliaryLable()
        {
            int removeCount = auxiliary_Labels.Count;
            auxiliary_Labels.Clear();

            if (removeCount > 0) NCurveUpdate();
        }

        #endregion

        #region Mark Text

        public List<NMarkText> markTexts;

        /// <summary>
        /// 新增一个标记的文本信息
        /// </summary>
        /// <param name="markText">文本标记信息</param>
        public void AddMarkText(NMarkText markText)
        {
            this.markTexts.Add(markText);
            if (data_list.Count > 0)
            {
                this.NCurveUpdate();
            }
        }

        /// <summary>
        /// 移除一个标记的文本信息
        /// </summary>
        /// <param name="markText">文本标记信息</param>
        public void RemoveMarkText(NMarkText markText)
        {
            this.markTexts.Remove(markText);
            if (data_list.Count > 0)
            {
                this.NCurveUpdate();
            }
        }

        /// <summary>
        /// 移除所有的标记的文本信息
        /// </summary>
        public void RemoveAllMarkText()
        {
            this.markTexts.Clear();
            if (data_list.Count > 0)
            {
                this.NCurveUpdate();
            }
        }

        #endregion

        #region Private Method

        private bool IsNeedPaintDash(double paintValue)
        {
            // 遍历所有的数据组
            for (int i = 0; i < auxiliary_lines.Count; i++)
            {
                if (Math.Abs(auxiliary_lines[i].PaintValue - paintValue) < FontSize + 3)
                {
                    // 与辅助线冲突，不需要绘制
                    return false;
                }
            }

            // 需要绘制虚线
            return true;
        }

        private int CalculateDataCountByOffect(double offect)
        {
            if (IntervalAbscissaText > 0) return IntervalAbscissaText;

            if (offect > 40) return 1;
            offect = 40f / offect;
            return (int)Math.Ceiling(offect);
        }

        private void NCurveUpdate()
        {
            canvas1.Children.Clear();

            int width_totle = (int)ActualWidth + 1;
            int heigh_totle = (int)ActualHeight + 1;

            if (width_totle < 120 || heigh_totle < 60) return;
            int offect_left = 50;
            int offect_right = 50;
            int offect_up = 25;
            int offect_down = 25;

            // 绘制极轴
            Point[] pointsCoordinate = new Point[] {
                new Point(offect_left-1, offect_up - 8),
                new Point(offect_left-1, heigh_totle - offect_down),
                new Point(width_totle - offect_right, heigh_totle - offect_down),
                new Point(width_totle - offect_right, offect_up - 8)
            };

            WpfUtils.DrawLine(canvas1, pointsCoordinate[0], pointsCoordinate[1], ColorLinesAndText, 1d);
            WpfUtils.DrawLine(canvas1, pointsCoordinate[1], pointsCoordinate[2], ColorLinesAndText, 1d);

            if (string.IsNullOrEmpty(Title) && data_list.Count > 0)
            {
                // 绘制曲线名称
                float x_start = offect_left + 10;
                foreach (var item in data_list)
                {
                    if (item.Value.Visible)
                    {
                        Color textColor = item.Value.LineRenderVisiable ? item.Value.LineColor : Color.FromArgb((byte)80, (byte)item.Value.LineColor.R, (byte)item.Value.LineColor.G, (byte)item.Value.LineColor.B);
                        WpfUtils.DrawLine(canvas1, x_start, 11, x_start + 30, 11, textColor, 1d);
                        WpfUtils.DrawEllipse(canvas1, x_start + 8, 4, 14, 14, textColor, 1d);
                        WpfUtils.DrawString(canvas1, item.Key, textColor, x_start + 35, 10 - 20, 120, 40, HorizontalAlignment.Left, VerticalAlignment.Center);
                        x_start += CurveNameWidth;
                    }
                }
            }

            // 绘制特殊的标记文本
            for (int i = 0; i < auxiliary_Labels.Count; i++)
            {
                if (!string.IsNullOrEmpty(auxiliary_Labels[i].Text))
                {
                    int start = auxiliary_Labels[i].LocationX > 1 ? (int)auxiliary_Labels[i].LocationX : (int)(auxiliary_Labels[i].LocationX * width_totle);

                    Point[] labelBounds = new Point[]
                    {
                        new Point(start, 11),
                        new Point(start + 10, 20),
                        new Point(start + 10, 0),
                        new Point(start, 11),
                    };
                    WpfUtils.FillPolygon(canvas1, labelBounds, auxiliary_Labels[i].TextBack);
                    Label label = new Label();
                    label.Height = 20;
                    label.Foreground = new SolidColorBrush(auxiliary_Labels[i].TextBrush);
                    label.Background = new SolidColorBrush(auxiliary_Labels[i].TextBack);
                    label.HorizontalContentAlignment = HorizontalAlignment.Left;
                    label.VerticalContentAlignment = VerticalAlignment.Center;
                    label.Content = auxiliary_Labels[i].Text;
                    label.Padding = new Thickness(0, 0, 4, 0);
                    canvas1.Children.Add(label);
                    label.Style = null;
                    Canvas.SetLeft(label, start + 10);
                    Canvas.SetTop(label, 0);
                }
            }

            // 画三角
            WpfUtils.FillTriangle(canvas1, new Point(offect_left - 1, offect_up - 8), ColorLinesAndText, 4, GraphDirection.Upward);

            // 计算所有辅助线的实际值
            for (int i = 0; i < auxiliary_lines.Count; i++)
            {
                auxiliary_lines[i].PaintValue = NHelper.ComputePaintLocationY(ValueMaxLeft, ValueMinLeft, (heigh_totle - offect_up - offect_down), auxiliary_lines[i].Value) + offect_up;
            }

            // 绘制刻度线，以及刻度文本
            for (int i = 0; i <= ValueSegment; i++)
            {
                double valueTmpLeft = i * (ValueMaxLeft - ValueMinLeft) / ValueSegment + ValueMinLeft;
                double paintTmp = NHelper.ComputePaintLocationY(ValueMaxLeft, ValueMinLeft, (heigh_totle - offect_up - offect_down), valueTmpLeft) + offect_up;
                if (IsNeedPaintDash(paintTmp))
                {
                    // 左坐标轴
                    WpfUtils.DrawLine(canvas1, offect_left - 4, paintTmp, offect_left - 1, paintTmp, ColorLinesAndText, 1d);
                    WpfUtils.DrawString(canvas1, valueTmpLeft.ToString(), ColorLinesAndText, 0, paintTmp - 20, offect_left - 4, 40, HorizontalAlignment.Right, VerticalAlignment.Center);

                    if (i > 0 && IsRenderDashLine) WpfUtils.DrawLine(canvas1, offect_left, paintTmp, width_totle - offect_right, paintTmp, ColorDashLines, 1d, new double[] { 5d, 5d });
                }
            }

            // 绘制纵向虚线信息
            if (IsRenderDashLine)
            {
                if (IsAbscissaStrech)
                {
                    // 拉伸模式下，因为错位是均匀的，所以根据数据来显示
                    float offect = (width_totle - offect_left - offect_right) * 1.0f / (StrechDataCountMax - 1);
                    int dataCount = CalculateDataCountByOffect(offect);


                    for (int i = 0; i < StrechDataCountMax; i += dataCount)
                    {
                        if (i > 0 && i < StrechDataCountMax - 1)
                        {
                            WpfUtils.DrawLine(canvas1, i * offect + offect_left, offect_up, i * offect + offect_left, heigh_totle - offect_down - 1, ColorDashLines, 1d, new double[] { 5d, 5d });
                        }

                        if (data_text != null)
                        {
                            if (i < data_text.Length && ((i * offect + offect_left) < (data_text.Length - 1) * offect + offect_left - 40))
                            {
                                WpfUtils.DrawString(canvas1, data_text[i], ColorLinesAndText, (i * offect) + offect_left - 100, heigh_totle - offect_down + 1, 200, offect_down, HorizontalAlignment.Center, VerticalAlignment.Top);
                            }
                        }
                    }

                    if (data_text?.Length > 1)
                    {
                        if (data_text.Length < StrechDataCountMax)
                        {
                            // 绘制最前端的虚线
                            WpfUtils.DrawLine(canvas1, (data_text.Length - 1) * offect + offect_left, offect_up, (data_text.Length - 1) * offect + offect_left, heigh_totle - offect_down - 1, ColorDashLines, 1d, new double[] { 5d, 5d });
                        }

                        WpfUtils.DrawString(canvas1, data_text[data_text.Length - 1], ColorLinesAndText, ((data_text.Length - 1) * offect + offect_left) - 100, heigh_totle - offect_down + 1, 200, offect_down, HorizontalAlignment.Center, VerticalAlignment.Top);

                    }
                }
                else
                {
                    int countTmp = width_totle - offect_left - offect_right + 1;
                    // 普通模式下绘制图形
                    for (int i = offect_left; i < width_totle - offect_right; i += IntervalAbscissaText)
                    {
                        if (i != offect_left)
                        {
                            WpfUtils.DrawLine(canvas1, i, offect_up, i, heigh_totle - offect_down - 1, ColorDashLines, 1d, new double[] { 5d, 5d });
                        }

                        if (data_text != null)
                        {
                            int right_limit = countTmp > data_text.Length ? data_text.Length : countTmp;

                            if ((i - offect_left) < data_text.Length)
                            {
                                if ((right_limit - (i - offect_left)) > 40)
                                {
                                    // 点数大于1的时候才绘制
                                    if (data_text.Length <= countTmp)
                                    {
                                        WpfUtils.DrawString(canvas1, data_text[i - offect_left], ColorLinesAndText, i - 100, heigh_totle - offect_down + 1, 200, offect_down, HorizontalAlignment.Center, VerticalAlignment.Top);
                                    }
                                    else
                                    {
                                        WpfUtils.DrawString(canvas1, data_text[i - offect_left + data_text.Length - countTmp], ColorLinesAndText, i - 100, heigh_totle - offect_down + 1, 200, offect_down, HorizontalAlignment.Center, VerticalAlignment.Top);
                                    }
                                }
                            }
                        }
                    }

                    if (data_text?.Length > 1)
                    {
                        if (data_text.Length < countTmp)
                        {
                            // 绘制最前端的虚线
                            WpfUtils.DrawLine(canvas1, (data_text.Length + offect_left - 1), offect_up, (data_text.Length + offect_left - 1), heigh_totle - offect_down - 1, ColorDashLines, 1d, new double[] { 5d, 5d });

                            WpfUtils.DrawString(canvas1, data_text[data_text.Length - 1], ColorLinesAndText, (data_text.Length + offect_left - 1) - 100, heigh_totle - offect_down + 1, 200, offect_down, HorizontalAlignment.Center, VerticalAlignment.Top);
                        }
                        else
                        {
                            WpfUtils.DrawString(canvas1, data_text[data_text.Length - 1], ColorLinesAndText, width_totle - offect_right - 100, heigh_totle - offect_down + 1, 200, offect_down, HorizontalAlignment.Center, VerticalAlignment.Top);
                        }
                    }
                }
            }


            // 绘制辅助线信息
            for (int i = 0; i < auxiliary_lines.Count; i++)
            {
                // 左坐标轴
                WpfUtils.DrawLine(canvas1, offect_left - 4, auxiliary_lines[i].PaintValue, offect_left - 1, auxiliary_lines[i].PaintValue, ColorDashLines, 1d);

                WpfUtils.DrawString(canvas1, auxiliary_lines[i].Value.ToString(), ColorLinesAndText, 0, auxiliary_lines[i].PaintValue - 20, offect_left - 4, 40, HorizontalAlignment.Right, VerticalAlignment.Center);

                if (auxiliary_lines[i].IsDashStyle)
                    WpfUtils.DrawLine(canvas1, offect_left, auxiliary_lines[i].PaintValue, width_totle - offect_right, auxiliary_lines[i].PaintValue, auxiliary_lines[i].LineColor, auxiliary_lines[i].LineThickness, new double[] { auxiliary_lines[i].LineThickness * 5d, auxiliary_lines[i].LineThickness * 5d });
                else
                    WpfUtils.DrawLine(canvas1, offect_left, auxiliary_lines[i].PaintValue, width_totle - offect_right, auxiliary_lines[i].PaintValue, auxiliary_lines[i].LineColor, auxiliary_lines[i].LineThickness);
            }


            //绘制线条
            if (IsAbscissaStrech)
            {
                // 绘制标记文本
                foreach (var markText in markTexts)
                {
                    foreach (var line in data_list)
                    {
                        if (!line.Value.Visible) continue;
                        if (!line.Value.LineRenderVisiable) continue;
                        if (line.Key != markText.CurveKey) continue;
                        if (line.Value.Data?.Length > 1)
                        {
                            float offect = (width_totle - offect_left - offect_right) * 1.0f / (StrechDataCountMax - 1);

                            if (markText.Index >= 0 && markText.Index < line.Value.Data.Length)
                            {
                                Point center = new Point(offect_left + markText.Index * offect,
                                    NHelper.ComputePaintLocationY(ValueMaxLeft, ValueMinLeft,
                                    (heigh_totle - offect_up - offect_down), line.Value.Data[markText.Index]) + offect_up);
                                WpfUtils.FillEllipse(canvas1, center.X - 3, center.Y - 3, 6, 6, markText.CircleColor);

                                MarkTextPositionStyle markTextPosition = markText.PositionStyle == MarkTextPositionStyle.Auto ?
                                    NMarkText.CalculateDirectionFromDataIndex(line.Value.Data, markText.Index) : markText.PositionStyle;

                                switch (markTextPosition)
                                {
                                    case MarkTextPositionStyle.Left: WpfUtils.DrawString(canvas1, markText.MarkText, markText.TextColor, center.X - 100, center.Y - 20, 100 - NMarkText.MarkTextOffect, 40, HorizontalAlignment.Right, VerticalAlignment.Center); break;
                                    case MarkTextPositionStyle.Up: WpfUtils.DrawString(canvas1, markText.MarkText, markText.TextColor, center.X - 100, center.Y - 40 - NMarkText.MarkTextOffect, 200, 40, HorizontalAlignment.Center, VerticalAlignment.Bottom); break;
                                    case MarkTextPositionStyle.Right: WpfUtils.DrawString(canvas1, markText.MarkText, markText.TextColor, center.X + NMarkText.MarkTextOffect, center.Y - 20, 100, 40, HorizontalAlignment.Left, VerticalAlignment.Center); break;
                                    case MarkTextPositionStyle.Down: WpfUtils.DrawString(canvas1, markText.MarkText, markText.TextColor, center.X - 100, center.Y + NMarkText.MarkTextOffect, 200, 40, HorizontalAlignment.Center, VerticalAlignment.Top); break;
                                    default: break;
                                }
                            }
                        }
                    }
                }

                // 横坐标充满图形
                foreach (var line in data_list.Values)
                {
                    if (!line.Visible) continue;
                    if (!line.LineRenderVisiable) continue;

                    if (line.Data?.Length > 1)
                    {
                        float offect = (width_totle - offect_left - offect_right) * 1.0f / (StrechDataCountMax - 1);

                        // 点数大于1的时候才绘制
                        Point[] points = new Point[line.Data.Length];
                        for (int i = 0; i < line.Data.Length; i++)
                        {
                            points[i].X = offect_left + i * offect;
                            points[i].Y = NHelper.ComputePaintLocationY(ValueMaxLeft, ValueMinLeft,
                                (heigh_totle - offect_up - offect_down), line.Data[i]) + offect_up;

                            if (!string.IsNullOrEmpty(line.MarkText[i]))
                            {
                                WpfUtils.FillEllipse(canvas1, points[i].X - 3, points[i].Y - 3, 6, 6, line.LineColor);

                                MarkTextPositionStyle markTextPosition = NMarkText.CalculateDirectionFromDataIndex(line.Data, i);

                                switch (markTextPosition)
                                {
                                    case MarkTextPositionStyle.Left: WpfUtils.DrawString(canvas1, line.MarkText[i], line.LineColor, points[i].X - 100, points[i].Y - 20, 100 - NMarkText.MarkTextOffect, 40, HorizontalAlignment.Right, VerticalAlignment.Center); break;
                                    case MarkTextPositionStyle.Up: WpfUtils.DrawString(canvas1, line.MarkText[i], line.LineColor, points[i].X - 100, points[i].Y - 40 - NMarkText.MarkTextOffect, 200, 40, HorizontalAlignment.Center, VerticalAlignment.Bottom); break;
                                    case MarkTextPositionStyle.Right: WpfUtils.DrawString(canvas1, line.MarkText[i], line.LineColor, points[i].X + NMarkText.MarkTextOffect, points[i].Y - 20, 100, 40, HorizontalAlignment.Left, VerticalAlignment.Center); break;
                                    case MarkTextPositionStyle.Down: WpfUtils.DrawString(canvas1, line.MarkText[i], line.LineColor, points[i].X - 100, points[i].Y + NMarkText.MarkTextOffect, 200, 40, HorizontalAlignment.Center, VerticalAlignment.Top); break;
                                    default: break;
                                }
                            }
                        }

                        WpfUtils.DrawLines(canvas1, points, line, PointsRadius);
                    }
                }
            }
            else
            {
                // 绘制标记文本
                foreach (var markText in markTexts)
                {
                    foreach (var line in data_list)
                    {
                        if (!line.Value.Visible) continue;
                        if (!line.Value.LineRenderVisiable) continue;

                        if (line.Key != markText.CurveKey) continue;
                        if (line.Value.Data?.Length > 1)
                        {
                            if (markText.Index >= 0 && markText.Index < line.Value.Data.Length)
                            {
                                Point center = new Point(offect_left + markText.Index,
                                    NHelper.ComputePaintLocationY(ValueMaxLeft, ValueMinLeft,
                                    (heigh_totle - offect_up - offect_down), line.Value.Data[markText.Index]) + offect_up);

                                WpfUtils.FillEllipse(canvas1, center.X - 3, center.Y - 3, 6, 6, markText.CircleColor);


                                MarkTextPositionStyle markTextPosition = markText.PositionStyle == MarkTextPositionStyle.Auto ?
                                    NMarkText.CalculateDirectionFromDataIndex(line.Value.Data, markText.Index) : markText.PositionStyle;

                                switch (markTextPosition)
                                {
                                    case MarkTextPositionStyle.Left: WpfUtils.DrawString(canvas1, markText.MarkText, markText.TextColor, center.X - 100, center.Y - 20, 100 - NMarkText.MarkTextOffect, 40, HorizontalAlignment.Right, VerticalAlignment.Center); break;
                                    case MarkTextPositionStyle.Up: WpfUtils.DrawString(canvas1, markText.MarkText, markText.TextColor, center.X - 100, center.Y - 40 - NMarkText.MarkTextOffect, 200, 40, HorizontalAlignment.Center, VerticalAlignment.Bottom); break;
                                    case MarkTextPositionStyle.Right: WpfUtils.DrawString(canvas1, markText.MarkText, markText.TextColor, center.X + NMarkText.MarkTextOffect, center.Y - 20, 100, 40, HorizontalAlignment.Left, VerticalAlignment.Center); break;
                                    case MarkTextPositionStyle.Down: WpfUtils.DrawString(canvas1, markText.MarkText, markText.TextColor, center.X - 100, center.Y + NMarkText.MarkTextOffect, 200, 40, HorizontalAlignment.Center, VerticalAlignment.Top); break;
                                    default: break;
                                }
                            }
                        }
                    }
                }


                // 横坐标对应图形
                foreach (var line in data_list.Values)
                {
                    if (!line.Visible) continue;
                    if (!line.LineRenderVisiable) continue;

                    if (line.Data?.Length > 1)
                    {
                        int countTmp = width_totle - offect_left - offect_right + 1;
                        List<Point> listPoints = new List<Point>(line.Data.Length);
                        // 点数大于1的时候才绘制
                        if (line.Data.Length <= countTmp)
                        {
                            for (int i = 0; i < line.Data.Length; i++)
                            {
                                if (!double.IsNaN(line.Data[i]))
                                {
                                    Point point = new Point();
                                    point.X = offect_left + i;
                                    point.Y = NHelper.ComputePaintLocationY(ValueMaxLeft, ValueMinLeft,
                                    (heigh_totle - offect_up - offect_down), line.Data[i]) + offect_up;

                                    listPoints.Add(point);
                                    DrawMarkPoint(line.MarkText[i], point, line.LineColor, NMarkText.CalculateDirectionFromDataIndex(line.Data, i));
                                }
                                else
                                {
                                    WpfUtils.DrawLines(canvas1, listPoints.ToArray(), line, PointsRadius);
                                    listPoints.Clear();
                                }
                            }
                        }
                        else
                        {
                            for (int i = 0; i < countTmp; i++)
                            {
                                int index = i + line.Data.Length - countTmp;
                                if (!double.IsNaN(line.Data[i]))
                                {
                                    Point point = new Point();
                                    point.X = offect_left + i;
                                    point.Y = NHelper.ComputePaintLocationY(ValueMaxLeft, ValueMinLeft,
                                        (heigh_totle - offect_up - offect_down), line.Data[index]) + offect_up;

                                    listPoints.Add(point);
                                    DrawMarkPoint(line.MarkText[index], point, line.LineColor, NMarkText.CalculateDirectionFromDataIndex(line.Data, index));
                                }
                                else
                                {
                                    WpfUtils.DrawLines(canvas1, listPoints.ToArray(), line, PointsRadius);
                                    listPoints.Clear();
                                }
                            }
                        }

                        WpfUtils.DrawLines(canvas1, listPoints.ToArray(), line, PointsRadius);
                    }
                }
            }
        }


        private void DrawMarkPoint(string markText, Point center, Color color, MarkTextPositionStyle markTextPosition)
        {
            if (!string.IsNullOrEmpty(markText))
            {
                WpfUtils.FillEllipse(canvas1, center.X - 3, center.Y - 3, 6, 6, color);

                switch (markTextPosition)
                {
                    case MarkTextPositionStyle.Left: WpfUtils.DrawString(canvas1, markText, color, center.X - 100, center.Y - 20, 100 - NMarkText.MarkTextOffect, 40, HorizontalAlignment.Right, VerticalAlignment.Center); break;
                    case MarkTextPositionStyle.Up: WpfUtils.DrawString(canvas1, markText, color, center.X - 100, center.Y - 40 - NMarkText.MarkTextOffect, 200, 40, HorizontalAlignment.Center, VerticalAlignment.Bottom); break;
                    case MarkTextPositionStyle.Right: WpfUtils.DrawString(canvas1, markText, color, center.X + NMarkText.MarkTextOffect, center.Y - 20, 100, 40, HorizontalAlignment.Left, VerticalAlignment.Center); break;
                    case MarkTextPositionStyle.Down: WpfUtils.DrawString(canvas1, markText, color, center.X - 100, center.Y + NMarkText.MarkTextOffect, 200, 40, HorizontalAlignment.Center, VerticalAlignment.Top); break;
                    default: break;
                }
            }
        }

        #endregion

        #region Private Member

        private const int value_count_max = 4096;           // 缓存的数据的最大量
        private Random random = null;                       // 获取随机颜色使用

        #endregion
    }

}
